/**
 * Writed by yura and mak
 */

package wz.legend.handlers.farming;

import org.apache.commons.digester.CallMethodRule;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.Rule;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import wz.legend.util.IntegerCreationFactory;
import wz.legend.util.Utils;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: yura
 */
public class ItemManager {
    private static final Logger LOG = Logger.getLogger(ItemManager.class);

    private static Map<Integer, List<Integer>> KNOWN_ITEMS;

    private XPath path;
    private Document document;

    static {
        initKnownItems();
    }

    private static void initKnownItems() {
        try {
            Digester digester = new Digester();
            digester.addObjectCreate("professions", HashMap.class);

            digester.addFactoryCreate("professions/profession",
                    new IntegerCreationFactory("index"));
            digester.addObjectCreate("professions/profession", "class",
                    Object.class);
            digester.addFactoryCreate("professions/profession/item",
                    new IntegerCreationFactory("value"));
            digester.addSetNext("professions/profession/item", "add");

            Rule r = new CallMethodRule(2, "put", 2);
            digester.addRule("professions/profession", r);
            digester.addCallParam("professions/profession", 0, 1);
            digester.addCallParam("professions/profession", 1, true);

            InputStream stream = ItemManager.class.getClassLoader()
                    .getResourceAsStream("farmitems.xml");
            KNOWN_ITEMS = (Map<Integer, List<Integer>>) digester.parse(stream);
        } catch (Exception e) {
            LOG.error(e, e);
            throw new RuntimeException(e);
        }
    }

    public ItemManager(Document document) {
        this.document = document;
        path = XPathFactory.newInstance().newXPath();
    }

    public List<Node> getBotsList(boolean farmNearFight) throws Exception {
        StringBuffer query = new StringBuffer();
        query.append("/hunt/bots/bot[@sk!=2001");
        if(farmNearFight) {
            query.append(" and @fight_id=0");
        }
        query.append("]");
        return Utils.convertNodeList((NodeList) path.evaluate(query.toString(),
                document, XPathConstants.NODESET));
    }

    public List<Node> getFarmsList(int profession) throws Exception {
        StringBuffer query = new StringBuffer();
        query.append("/hunt/farm/item[@prof=").append(profession).append(
                " and @farming=0");
        query.append(" and @x<1500 and @y<1500 and @x>0 and @y>0");
        query.append(" and (");
        for (int i = 0; i < KNOWN_ITEMS.get(profession).size(); i++) {
            query.append("@artikul_id=").append(
                    KNOWN_ITEMS.get(profession).get(i));
            if (i < KNOWN_ITEMS.get(profession).size() - 1)
                query.append(" or ");
        }
        query.append(")]");
        List<Node> list = Utils.convertNodeList((NodeList) path.evaluate(
                query.toString(), document, XPathConstants.NODESET));
        
        Collections.sort(list, new ItemComparator(profession));
        return list;
    }

    public Node findFarm(int id) throws Exception {
        StringBuffer query = new StringBuffer();
        query.append("/hunt/farm/item[@num=").append(id).append("]");
        return (Node) path.evaluate(query.toString(), document,
                XPathConstants.NODE);
    }

    private class ItemComparator implements Comparator<Node> {
        private int profession;

        public ItemComparator(int profession) {
            this.profession = profession;
        }

        public int compare(Node o1, Node o2) {
            int articul_index1 = KNOWN_ITEMS.get(profession).indexOf(
                    Utils.getAttributeInt(o1, "artikul_id"));
            int articul_index2 = KNOWN_ITEMS.get(profession).indexOf(
                    Utils.getAttributeInt(o2, "artikul_id"));

            return articul_index1 - articul_index2;
        }
    }
}
